import java.util.*;

enum Id { PROGRAM, 
	  INT, CHAR, VOID, 
	  IDENTIFIER, INTEGER_LITERAL, FUNCALL, 
	  VARDEC, ARRAYVAR_DEC, FUNDEC, 
	  FORMAL_PARAMETERS, ACTUAL_PARAMETERS, LOCAL_VARIABLES, 
	  FUNBODY, COMPOUND_STATEMENT,	  
          ASSIGNMENT, ANDAND, RELOP, ADDOP, MULOP, UNOP, EQOP,
	  WHILE, IF, ELSE, RETURN
	}

public class Node {
    
    private Id id;

    private List<Node> children;

    private Position position;

    public Node (Id _id) {
	id = _id;
	children = new ArrayList<Node>();
    }

    public Node (Id _id, List<Node> _children)
    {
	id = _id;
	children = _children;
    }

    public void add(Node child) {
	children.add(child);
    }

    public int numberOfChildren() {
	return children.size();
    }

    public Node getChild(int i) {
	return children.get(i);
    }

    public Node getChild(int i, int n) {
	if (n!=children.size()) 
	    throw new IllegalArgumentException ();
	return children.get(i);
    }

    public Id getId() {
	return id;
    }

    public void setPosition(Position p) {
	position = p;
    }

    public Position getPosition () {
	return position;
    }

    public boolean hasChild()
    {
	if(children != null)
	    return true;
	else
	    return false;
    }

    public void printHead(String prefix, String suffix) {
	System.out.print(prefix+id);
	if (position != null) {
	    System.out.print(" @ "+position);
	}
	System.out.println(" "+suffix);
    }

    public void printChildren(String prefix) {
	if (children != null) {
	    for (Node n : children) {
		if (n != null) {
		    n.print(prefix + " ");
		}
	    }
	}
    }

    public void print(String prefix, String suffix) {
	printHead(prefix, suffix);
	printChildren(prefix);
    }

    public void print(String prefix) {
	print(prefix, "");
    }

    public int getIntegerLiteral(String integer_constant)
    {
	int value = 0;
	if(integer_constant.charAt(0)== '\'')
	{
	if(integer_constant.charAt(1)== '\\')
        {
	    switch(integer_constant.charAt(2))
	    {
	        case 'n' : 
		    value = 10; break;
	        case 'r' :
	            value = 13; break;
	        case 'f' :
	            value = 12; break;
	        case 't' :
	            value = 9; break;
	    }

        }
        else 
        {	    
	    switch(integer_constant.charAt(1))
	    {

	        case '0':   
		    value = 48; break;
	        case '1':   
		    value = 49; break;
	        case '2':   
		    value = 50; break;
	        case '3':   
		    value = 51; break;
	        case '4':   
		    value = 52; break;
	        case '5':   
		    value = 53; break;
	        case '6':   
		    value = 54; break;
	        case '7':   
		    value = 55; break;
	        case '8':   
		    value = 56; break;		
	        case '9':   
		    value = 57; break;		
	        case 'a': 
		    value = 97; break;
	        case 'b':
		    value = 98; break;
	        case 'c':
		    value = 99; break;
	        case 'd':
		    value = 100; break;
	        case 'e':
		    value = 101; break;
	        case 'f':
		    value = 102; break;
	        case 'g':
		    value = 103; break;
	        case 'h':
		    value = 104; break;
	        case 'i':
		    value = 105; break;
	        case 'j':
		    value = 106; break;
	        case 'k':
		    value = 107; break;
	        case 'l':
		    value = 108; break;
	        case 'm':
		    value = 109; break;
	        case 'n':
		    value = 110; break;
	        case 'o':
		    value = 111; break;
	        case 'p':
		    value = 112; break;
	        case 'q':
		    value = 113; break;
	        case 'r':
		    value = 114; break;
	        case 's':
		    value = 115; break;
	        case 't':
		    value = 116; break;
	        case 'u':
		    value = 117; break;
	        case 'v':
		    value = 118; break;
	        case 'w':
		    value = 119; break;
	        case 'x':
		    value = 120; break;
	        case 'y':
		    value = 121; break;
	        case 'z':
		    value = 122; break;
	        case 'A': 
		    value = 65; break;
	        case 'B': 
		    value = 66; break;
	        case 'C': 
		    value = 67; break;
	        case 'D': 
		    value = 68; break;
	        case 'E': 
		    value = 69; break;
	        case 'F': 
		    value = 70; break;
	        case 'G': 
		    value = 71; break;
	        case 'H': 
		    value = 72; break;
	        case 'I': 
		    value = 73; break;
	        case 'J': 
		    value = 74; break;
	        case 'K': 
		    value = 75; break;
	        case 'L': 
		    value = 76; break;
	        case 'M': 
		    value = 77; break;
	        case 'N': 
		    value = 78; break;
	        case 'O': 
		    value = 79; break;
	        case 'P': 
		    value = 80; break;
	        case 'Q': 
		    value = 81; break;
	        case 'R': 
		    value = 82; break;
	        case 'S': 
		    value = 83; break;
	        case 'T': 
		    value = 84; break;
	        case 'U': 
		    value = 85; break;
	        case 'V': 
		    value = 86; break;
	        case 'W': 
		    value = 87; break;
	        case 'X': 
		    value = 88; break;
	        case 'Y': 
		    value = 89; break;
	        case 'Z': 
		    value = 90; break;
	        case ' ': 
		    value = 32; break;
	        case '!': 
		    value = 33; break;
	        case '\"': 
		    value = 34; break;
	        case '#': 
		    value = 35; break;
	        case '$': 
		    value = 36; break;
	        case '%': 
		    value = 37; break;
	        case '&': 
		    value = 38; break;
	        case '\'': 
		    value = 39; break;
	        case '(': 
		    value = 40; break;
	        case ')': 
		    value = 41; break;
	        case '*': 
		    value = 42; break;
	        case '+': 
		    value = 43; break;
	        case ',': 
		    value = 44; break;
		case '-':
		    value = 45; break;
	        case '.':
		    value = 46; break;
	        case '/':
		    value = 47; break;
	        case ':': 
		    value = 58; break;
	        case ';': 
		    value = 59; break;
	        case '<': 
		    value = 60; break;
	        case '=': 
		    value = 61; break;
	        case '>': 
		    value = 62; break; 
	        case '?': 
		    value = 63; break;
	        case '@': 
		    value = 64; break; 
	        case '[': 
		    value = 91; break; 
	        case '\\': 
		    value = 92; break; 
	        case ']': 
		    value = 93; break;
	        case '^':
		    value = 94; break;
	        case '_': 
		    value = 95; break;
	        case '`': 
		    value = 96; break;
	        case '{': 
		    value = 123; break;
	        case '|': 
		    value = 124; break; 
	        case '}': 
		    value = 125; break;
	        case '~':
		    value = 126; break;
	    }
	}
	}
	else
	{
	    value = Integer.parseInt(integer_constant);
	}

	return value;
    }

}

class Program extends Node
{
    public Program(List<Node> tdl)
    {
	super(Id.PROGRAM, tdl);	
    }
}


class FormalParameters extends Node
{
    public FormalParameters(List<Node> vdl)
    {
	super(Id.FORMAL_PARAMETERS, vdl);
    }
}

class ActualParameters extends Node
{
    public ActualParameters(List<Node> vdl)
    {
	super(Id.ACTUAL_PARAMETERS, vdl);
    }
}


class LocalVariables extends Node
{
    public LocalVariables(List<Node> vdl)
    {
	super(Id.LOCAL_VARIABLES, vdl);
    }
}

class FunctionBody extends Node
{
    public FunctionBody(List<Node> stmts)
    {
	super(Id.FUNBODY, stmts);
    }
}

class CompoundStatement extends Statement
{
    public CompoundStatement (List<Node> stmts) 
    {
	super(Id.COMPOUND_STATEMENT, stmts);
    }
}



class TypeNode extends Node
{
    String name;
    public TypeNode (Id _id) 
    {
	 super(_id);
    }

    public String getName()
    {
	return name;
    }

}

class Identifier extends Node
{
    String name;
    public Identifier (String _name)
    {
	super(Id.IDENTIFIER);
	name = _name;
    }

    public void print(String prefix) {
	print(prefix, ": " + name);
    }

    public String getName()
    {
	return name;
    }
}

class IntegerTypeNode extends TypeNode
{
    public IntegerTypeNode()
    {
	super(Id.INT);
	name = "int";
    }
}

class CharTypeNode extends TypeNode
{
    public CharTypeNode()
    {
	super(Id.CHAR);
	name = "char";
    }
}

class VoidTypeNode extends TypeNode
{
    private String name = "void";
    public VoidTypeNode()
    {
	super(Id.VOID);
    }

    public String getName()
    {
	return name;
    }
}

class IntegerLiteral extends Node
{
    private int value;

    public IntegerLiteral(String integer_constant)
    {
	super(Id.INTEGER_LITERAL);
	value = getIntegerLiteral(integer_constant);	
    }

    public int getValue()
    {
	return value;
    }

    public void print(String prefix) {
	print(prefix, ": " + value);
    }

}

class Declaration extends Node
{
    public Declaration (Id _id) {
	 super(_id);
    }
}

class FunDeclaration extends Declaration
{
    public FunDeclaration(TypeNode t, Identifier i, FormalParameters formalsList, LocalVariables localsList, FunctionBody statemets)
    {
	super(Id.FUNDEC);
	add(t);
	add(i);
	add(formalsList);
	add(localsList);
	add(statemets);
    }
}

class VarDeclaration extends Declaration
{
    public VarDeclaration(TypeNode t, Identifier i)
    {
	super(Id.VARDEC);
	add(t);
	add(i);		
    }
}

class VoidDeclaration extends Declaration
{
    public VoidDeclaration()
    {
	super(Id.VOID);
    }
}

class ArrayVarDeclaration extends Declaration
{
    public ArrayVarDeclaration(TypeNode t, Identifier id, IntegerLiteral i)
    {
	super(Id.ARRAYVAR_DEC);
	add(t);
	add(id);
	add(i);		
    }

    public ArrayVarDeclaration(TypeNode t, Identifier id)
    {
	super(Id.ARRAYVAR_DEC);
	add(t);
	add(id);
    }
}

class Statement extends Node
{
    public Statement (Id _id) {
	 super(_id);
    }

    public Statement (Id _id,  List<Node> _children) {
	super(_id, _children);
    }
}

class ReturnStatement extends Statement
{
    public ReturnStatement(Expression e)
    {
	super(Id.RETURN);
	add(e);
    }
    
    public ReturnStatement()
    {
	super(Id.RETURN);
    }
}


class WhileStatement extends Statement
{
    public WhileStatement(Expression cond, Statement stmt)
    {
	super(Id.WHILE);
	add(cond);
	add(stmt);
    }
}

class IfStatement extends Statement
{
    public IfStatement(Expression cond, Statement stmt)
    {
	super(Id.IF);
	add(cond);
	add(stmt);
    }

    public IfStatement(Expression cond, Statement stmt, Statement stmt2)
    {
	super(Id.IF);
	add(cond);
	add(stmt);       
	add(stmt2);
    }
    
}

class ElseStatement extends Statement
{
    public ElseStatement(Statement stmt)
    {
	super(Id.ELSE);
 	add(stmt);
    }
}

class Expression extends Statement
{
    public Expression (Id _id) {
	 super(_id);
    }
}


class AndExpression extends Expression
{
    public AndExpression (Id _id) {
	 super(_id);
    }
}

class AssignmentExpression extends Expression
{
    public AssignmentExpression (Expression exp1, Expression exp2) {
	 super(Id.ASSIGNMENT);
	 add(exp1);
	 add(exp2);
    }
}

class EqualityExpression extends AndExpression
{
    String eqOp;
    public EqualityExpression (String _eqOp, Expression exp1, Expression exp2) {
	 super(Id.EQOP);
	 eqOp = _eqOp;
	 add(exp1);
	 add(exp2);
    }
    public EqualityExpression (Id _id) {
	 super(_id);
    }    
    public void print(String prefix) {
	print(prefix, ": " + eqOp);
    }
    public boolean isEQ(){
	if(eqOp.equals("=="))
	    return true;
	else return false;
    }
}

class AndAndExpression extends EqualityExpression
{
    public AndAndExpression (Expression exp1, Expression exp2) {
	 super(Id.ANDAND);
	 add(exp1);
	 add(exp2);
    }
    public void print(String prefix) {
	print(prefix, ": " + "&&");
    }
}

class RelationalExpression extends EqualityExpression
{
    String relOp;

    public RelationalExpression (String _relOp, Expression exp1, Expression exp2) {
	 super(Id.RELOP);
	 relOp = _relOp;
	 add(exp1);
	 add(exp2);
    }

    public RelationalExpression(Id _id)
    {
	 super(_id);    
    }

    public void print(String prefix) {
	print(prefix, ": " + relOp);
    }
    
    public boolean isGT(){
	if(relOp.equals(">"))
	    return true;
	else return false;
    }
    public boolean isLT(){
	if(relOp.equals("<"))
	    return true;
	else return false;
    }
    public boolean isGTEQ(){
	if(relOp.equals(">="))
	    return true;
	else return false;
    }
    public boolean isLTEQ(){
	if(relOp.equals("<="))
	    return true;
	else return false;
    }
}


class AdditiveExpression extends RelationalExpression
{
    String addOp;
    public AdditiveExpression (String _addOp, Expression exp1, Expression exp2) {
	 super(Id.ADDOP);
	 addOp = _addOp;
	 add(exp1);
	 add(exp2);
    }
    public AdditiveExpression(Id _id)
    {
	 super(_id);    
    }
    public void print(String prefix) {
	print(prefix, ": " + addOp);
    }
    public boolean isAdd(){
	if(addOp.charAt(0) == '+')
	    return true;
	else return false;
    }
}

class MultiplicativeExpression extends AdditiveExpression
{
    String mulOp;
    public MultiplicativeExpression (String _mulOp, Expression exp1, Expression exp2) {
	 super(Id.MULOP);
	 mulOp = _mulOp;
	 add(exp1);
	 add(exp2);
    }
    public MultiplicativeExpression(Id _id)
    {
	 super(_id);   
    }
    public void print(String prefix) {
	print(prefix, ": " + mulOp);
    }
    public boolean isMUL(){
	if(mulOp.charAt(0) == '*')
	    return true;
	else return false;
    }

    public boolean isDIV()
    {
	return !isMUL();
    }
    
}

class UnaryExpression extends MultiplicativeExpression
{
    String unOp;
    public UnaryExpression (String _unOp, Expression exp1)
    {	
	super(Id.UNOP);
	unOp = _unOp;

	add(exp1);
    }

    public UnaryExpression(Id _id)
    {
	 super(_id);   
    }

    public void print(String prefix) {
	print(prefix, ": " + unOp);
    }

    public boolean isMINUS(){
	if(unOp.charAt(0) == '-')
	    return true;
	else return false;
    }
}

class BasicExpression extends UnaryExpression
{
    public BasicExpression(Id _id)
    {
	 super(_id);   
    }
}

class IntegerExpression extends BasicExpression
{
    private int value;

    public IntegerExpression(String integer_constant)
    {
	
	super(Id.INTEGER_LITERAL);
	value = getIntegerLiteral(integer_constant);
    }

    public int getValue()
    {
	return value;
    }

    public void print(String prefix) {
	print(prefix, ": " + value);
    }
}


class BasicIdentifierExpression extends BasicExpression
{
    String name;
    public BasicIdentifierExpression(String _name)
    {
	super(Id.IDENTIFIER);
	name = _name;
    }

    public String getName()
    {
	return name;
    }

}

class IdentifierExpression extends BasicIdentifierExpression
{

    public IdentifierExpression (String _name)
    {
	super(_name);
    }

    public void print(String prefix) {
	print(prefix, ": " + name);
    }
}

class ArrayIdentifierExpression extends BasicIdentifierExpression
{

    public  ArrayIdentifierExpression(String _name, Expression e)
    {
	super(_name);
	add(e);
    }

    public void print(String prefix) {
	print(prefix, ": " + name);
    }
}

class FunctionCall extends BasicExpression
{
    public FunctionCall(Identifier i, ActualParameters actualsList)
    {
	super(Id.FUNCALL);
	add(i);
	add(actualsList);
    }

    public FunctionCall(Identifier i)
    {
	super(Id.FUNCALL);
	add(i);
    }

    public void print(String prefix) {
	print(prefix, "");
    }
}
